package com.mlink.vs.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

/**
 * ZIP文件压缩和解压(要使用apache ant.jar以处理中文乱码)
 * 
 */
public class ZipUtil {

	/**
	 * 压缩文件file成zip文件zipFile
	 * 
	 * @param file
	 *            要压缩的文件
	 * @param zipFile
	 *            压缩文件存放地方
	 * @throws Exception
	 */
	public static void zip(File file, File zipFile) throws Exception {
		ZipOutputStream output = null;
		try {
			output = new ZipOutputStream(new FileOutputStream(zipFile));
			// 顶层目录开始
			zipFile(output, file, "");
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			// 关闭流
			if (output != null) {
				output.flush();
				output.close();
			}
		}
	}

	/**
	 * 压缩文件为zip格式
	 * 
	 * @param output
	 *            ZipOutputStream对象
	 * @param file
	 *            要压缩的文件或文件夹
	 * @param basePath
	 *            条目根目录
	 * @throws IOException
	 */
	public static void zipFile(ZipOutputStream output, File file,
			String basePath) throws IOException {
		FileInputStream input = null;
		try {
			// 文件为目录
			if (file.isDirectory()) {
				// 得到当前目录里面的文件列表
				File list[] = file.listFiles();
				basePath = basePath + (basePath.length() == 0 ? "" : "/")
						+ file.getName();
				// 循环递归压缩每个文件
				for (File f : list)
					zipFile(output, f, basePath);
			} else {
				// 压缩文件
				basePath = (basePath.length() == 0 ? "" : basePath + "/")
						+ file.getName();
				// System.out.println(basePath);
				output.putNextEntry(new ZipEntry(basePath));
				input = new FileInputStream(file);
				int readLen = 0;
				byte[] buffer = new byte[1024 * 8];
				while ((readLen = input.read(buffer, 0, 1024 * 8)) != -1)
					output.write(buffer, 0, readLen);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			// 关闭流
			if (input != null)
				input.close();
		}
	}

	/**
	 * 解压zip文件
	 * 
	 * @param zipFilePath
	 *            zip文件绝对路径
	 * @param unzipDirectory
	 *            解压到的目录
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public static void unzip(String zipFilePath, String unzipDirectory)
			throws Exception {
		// 定义输入输出流对象
		InputStream input = null;
		OutputStream output = null;
		try {
			// 创建文件对象
			File file = new File(zipFilePath);
			// 创建zip文件对象
			ZipFile zipFile = new ZipFile(file);
			// 创建本zip文件解压目录
			String name = file.getName().substring(0,
					file.getName().lastIndexOf("."));
			File unzipFile = new File(unzipDirectory + "/" + name);
			if (unzipFile.exists())
				unzipFile.delete();
			unzipFile.mkdir();
			// 得到zip文件条目枚举对象
			Enumeration zipEnum = zipFile.getEntries();
			// 定义对象
			ZipEntry entry = null;
			String entryName = null, path = null;
			String names[] = null;
			int length;
			// 循环读取条目
			while (zipEnum.hasMoreElements()) {
				// 得到当前条目
				entry = (ZipEntry) zipEnum.nextElement();
				entryName = new String(entry.getName());
				// 用/分隔条目名称
				names = entryName.split("\\/");
				length = names.length;
				path = unzipFile.getAbsolutePath();
				for (int v = 0; v < length; v++) {
					if (v < length - 1) // 最后一个目录之前的目录
						createDirectory(path += "/" + names[v] + "/");
					else { // 最后一个
						if (entryName.endsWith("/")) // 为目录,则创建文件夹
							createDirectory(unzipFile.getAbsolutePath() + "/"
									+ entryName);
						else { // 为文件,则输出到文件
							input = zipFile.getInputStream(entry);
							output = new FileOutputStream(new File(
									unzipFile.getAbsolutePath() + "/"
											+ entryName));
							byte[] buffer = new byte[1024 * 8];
							int readLen = 0;
							while ((readLen = input.read(buffer, 0, 1024 * 8)) != -1)
								output.write(buffer, 0, readLen);

							output.close();
						}
					}
				}
			}
			zipFile.close();
			// unzipFile.
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			// 关闭流
			if (input != null)
				input.close();
			if (output != null) {
				output.flush();
				output.close();
			}
		}
	}

	public static void createDirectory(String path) throws IOException {
		File file = new File(path);
		if (!file.exists()) {
			FileUtils.forceMkdir(file);
		}
	}

	/**
	 * 解压zip文件
	 * 
	 * @param zipFilePath
	 *            zip文件绝对路径
	 * @param unzipDirectory
	 *            解压到的目录
	 * @param flag
	 *            是否需要子目录
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public static boolean unzip(String zipFilePath, String unzipDirectory,
			Boolean flag) {
		// 定义输入输出流对象
		InputStream input = null;
		OutputStream output = null;
		// 默认创建子目录
		boolean needDirectory = true;
		if (flag != null) {
			needDirectory = flag;
		}
		try {
			// 创建文件对象
			File file = new File(zipFilePath);
			// 创建zip文件对象
			ZipFile zipFile = new ZipFile(file);
			// 创建本zip文件解压目录
			String name = file.getName().substring(0,
					file.getName().lastIndexOf("."));
			File unzipFile = null;
			if (needDirectory) {
				unzipFile = new File(unzipDirectory + "/" + name);
			} else {
				unzipFile = new File(unzipDirectory);
			}
			if (unzipFile.exists())
				unzipFile.delete();
			unzipFile.mkdir();
			// 得到zip文件条目枚举对象
			Enumeration zipEnum = zipFile.getEntries();
			// 定义对象
			ZipEntry entry = null;
			String entryName = null, path = null;
			String names[] = null;
			int length;
			// 循环读取条目
			while (zipEnum.hasMoreElements()) {
				// 得到当前条目
				entry = (ZipEntry) zipEnum.nextElement();
				entryName = new String(entry.getName());
				// 用/分隔条目名称
				names = entryName.split("\\/");
				length = names.length;
				path = unzipFile.getAbsolutePath();
				for (int v = 0; v < length; v++) {
					if (v < length - 1) // 最后一个目录之前的目录
						createDirectory(path += "/" + names[v] + "/");
					else { // 最后一个
						if (entryName.endsWith("/")) // 为目录,则创建文件夹
							createDirectory(unzipFile.getAbsolutePath() + "/"
									+ entryName);
						else { // 为文件,则输出到文件
							input = zipFile.getInputStream(entry);
							output = new FileOutputStream(new File(
									unzipFile.getAbsolutePath() + "/"
											+ entryName));
							byte[] buffer = new byte[1024 * 8];
							int readLen = 0;
							while ((readLen = input.read(buffer, 0, 1024 * 8)) != -1)
								output.write(buffer, 0, readLen);
							output.close();
						}
					}
				}
			}
			zipFile.close();
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			// 关闭流
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
					return false;
				}
			}

			if (output != null) {
				try {
					output.flush();
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
					return false;
				}

			}

		}
		return true;
	}
	
	/** 
     * 递归压缩文件夹 
     * @param srcRootDir 压缩文件夹根目录的子路径 
     * @param file 当前递归压缩的文件或目录对象 
     * @param zos 压缩文件存储对象 
     * @throws Exception 
     */  
    private static void zip(String srcRootDir, File file, ZipOutputStream zos) throws Exception  
    {  
        if (file == null)   
        {  
            return;  
        }                 
          
        //如果是文件，则直接压缩该文件  
        if (file.isFile())  
        {             
            int count, bufferLen = 1024;  
            byte data[] = new byte[bufferLen];  
              
            //获取文件相对于压缩文件夹根目录的子路径  
            String subPath = file.getAbsolutePath();  
            int index = subPath.indexOf(srcRootDir);  
            if (index != -1)   
            {  
                subPath = subPath.substring(srcRootDir.length() + File.separator.length());  
            }  
            ZipEntry entry = new ZipEntry(subPath);  
            zos.putNextEntry(entry);  
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));  
            while ((count = bis.read(data, 0, bufferLen)) != -1)   
            {  
                zos.write(data, 0, count);  
            }  
            bis.close();  
            zos.closeEntry();  
        }  
        //如果是目录，则压缩整个目录  
        else   
        {  
            //压缩目录中的文件或子目录  
            File[] childFileList = file.listFiles();  
            for (int n=0; n<childFileList.length; n++)  
            {  
                childFileList[n].getAbsolutePath().indexOf(file.getAbsolutePath());  
                zip(srcRootDir, childFileList[n], zos);  
            }  
        }  
    }  
	
	/** 
     * 对文件或文件目录进行压缩 
     * @param srcPath 要压缩的源文件路径。如果压缩一个文件，则为该文件的全路径；如果压缩一个目录，则为该目录的顶层目录路径 
     * @param zipPath 压缩文件保存的路径。注意：zipPath不能是srcPath路径下的子文件夹 
     * @param zipFileName 压缩文件名 
     * @throws Exception 
     */  
    public static void zip(String srcPath, String zipPath, String zipFileName) throws Exception  
    {  
        if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(zipPath) || StringUtils.isEmpty(zipFileName))  
        {  
            return;
        }  
        CheckedOutputStream cos = null;  
        ZipOutputStream zos = null;                       
        try  
        {  
            File srcFile = new File(srcPath);  
            //创建压缩文件保存的文件对象  
            String zipFilePath = zipPath + File.separator + zipFileName;  
            File zipFile = new File(zipFilePath);             
            if (zipFile.exists())  
            {  
                //检测文件是否允许删除，如果不允许删除，将会抛出SecurityException  
                SecurityManager securityManager = new SecurityManager();  
                securityManager.checkDelete(zipFilePath);  
                //删除已存在的目标文件  
                zipFile.delete();                 
            }  
              
            cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());  
            zos = new ZipOutputStream(cos);  
              
            //如果只是压缩一个文件，则需要截取该文件的父目录  
            String srcRootDir = srcPath;  
            if (srcFile.isFile())  
            {  
                int index = srcPath.lastIndexOf(File.separator);  
                if (index != -1)  
                {  
                    srcRootDir = srcPath.substring(0, index);  
                }  
            }  
            //调用递归压缩方法进行目录或文件压缩  
            zip(srcRootDir, srcFile, zos);  
            zos.flush();  
        }  
        catch (Exception e)   
        {  
            throw e;  
        }  
        finally   
        {             
            try  
            {  
                if (zos != null)  
                {  
                    zos.close();  
                }                 
            }  
            catch (Exception e)  
            {  
                e.printStackTrace();  
            }             
        }  
    } 

	/**
	 * 测试
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// unzip("d:/test.zip", "f:/");
		// System.out.println("over....................");
		// zip(new File("C:/config"), new File("d:/桌面.zip"));
		// System.out.println("over..............");
		String filePath = "D:\\uploads\\Android";
		String zipFilePath = "D:\\uploads\\android.zip";
		zip(new File(filePath), new File(zipFilePath));
	}

}
